<ControlGroup {help} {label} labelWidth="{labelWidth||'100px'}" {uid}>
    {#if hexColor}
    <ColorPickerInput
        on:change="update(event)"
        color="{hexColor}"
        bind:visible="open"
        palette="{palette}"
    />
    {/if} {#if customizable}
    <span class="custom-color-selector-head">
        <a
            href="#customize"
            on:click="toggle(event)"
            class="btn btn-small custom {expanded?'btn-primary':''}"
            role="button"
            >{__('controls / color / customize-colors', 'core')}</a
        >
    </span>
    {/if}
</ControlGroup>

{#if customizable && expanded}
<div class="custom-color-selector-body">
    <div class="custom-color-selector-list">
        {#if !compact}
        <h4>{__('controls / color / select-elements', 'core')}</h4>
        {/if}
        <ul class="dataseries unstyled">
            {#each colorKeys as k}
            <li
                on:click="toggleSelect(k.key, event)"
                class="{selected.indexOf(k.key) > -1 ? 'selected':''}"
                data-series="{k.key}"
            >
                <div class="color" style="background:{k.color}">{!k.defined ? '×' : ''}</div>
                <label>{k.key}</label>
            </li>
            {/each}
        </ul>
        <div class="selection-controls">
            {__('Select:', 'core')}
            <a href="#/select-all" on:click="selectAll(event)">{__('all', 'core')}</a>
            <a href="#/select-none" on:click="selectNone(event)">{__('none', 'core')}</a>
            <a href="#/select-invert" on:click="selectInvert(event)">{__('invert', 'core')}</a>
        </div>
    </div>
    <div class="custom-color-selector-aside">
        {#if !compact}
        <h4>{__('controls / color / choose-color', 'core')}</h4>
        {/if} {#if selected.length}
        <div class="selection-color-picker">
            <ColorPickerInput
                initial="{false}"
                reset="Reset"
                on:change="updateCustom(event)"
                color="{customColor}"
                bind:visible="openCustom"
                palette="{palette}"
            />
            {#if !compact}<button class="btn btn-color-reset" on:click="reset()">Reset</button>{/if}
        </div>
        {:else}
        <p class="mini-help">{@html __('controls / color / customize-colors / info', 'core')}</p>
        {/if}
        <button class="btn btn-color-reset" on:click="resetAll()">
            {__(compact ? 'controls / color / reset-all' : 'controls / color / reset-all-colors',
            'core')}
        </button>
    </div>
</div>
{/if}

<script>
    import ColorPickerInput from './ColorPickerInput.html';
    import ControlGroup from './ControlGroup.html';
    import purifyHtml from '@datawrapper/shared/purifyHtml.js';
    import { storeColor, getColor } from './utils/colorPicker';

    import clone from '@datawrapper/shared/clone';
    import get from '@datawrapper/shared/get';
    import { __ } from '@datawrapper/shared/l10n';
    import chroma from 'chroma-js';
    import { uniq } from 'underscore';

    export default {
        components: { ColorPickerInput, ControlGroup },
        data() {
            return {
                labelWidth: '100px',
                open: false,
                openCustom: false,
                customizable: false,
                expanded: false,
                keys: false,
                compact: false,
                axis: false,
                help: false,
                selected: [],
                custom: {},
                uid: ''
            };
        },
        computed: {
            colorKeys({ $vis, keys, customizable, axis, custom, palette }) {
                if (!$vis || !customizable) return [];
                return (
                    axis
                        ? uniq(
                              $vis.axes(true)[axis].type() === 'date'
                                  ? $vis.axes(true)[axis].raw() // raw values for date cols
                                  : $vis.axes(true)[axis].values() // fmt values else
                          )
                        : keys && keys.length
                        ? keys
                        : $vis.colorKeys
                        ? $vis.colorKeys()
                        : $vis.keys()
                ).map(k => {
                    k = stripTags(k);
                    return {
                        key: k,
                        defined: custom[k] !== undefined && custom[k] !== false,
                        color:
                            custom[k] !== undefined && custom[k] !== false
                                ? getColor(custom[k], palette)
                                : '#cccccc'
                    };
                });
            },
            palette({ $themeData }) {
                return get($themeData, 'colors.palette', []);
            },
            hexColor({ value, palette }) {
                return getColor(value, palette);
            },
            customColor({ selected, palette, custom }) {
                if (custom[selected[0]] === undefined) return false; // return false to reset the current color
                const realColors = selected
                    .filter(s => custom[s] !== undefined)
                    .map(s => getColor(custom[s], palette));
                if (!realColors.length) return false; // return false to reset the current color
                return chroma.average(realColors, 'lab'); // return a color value to set the current color
            }
        },
        helpers: { __ },
        methods: {
            update(color) {
                const { palette } = this.get();
                this.set({ value: storeColor(color, palette, true) });
            },
            updateCustom(color) {
                const { selected, palette, custom } = this.get();
                const custom2 = clone(custom);
                selected.forEach(k => {
                    if (color) {
                        custom2[k] = storeColor(color, palette, true);
                    } else {
                        delete custom2[k];
                    }
                });
                this.set({ custom: custom2 });
            },
            toggle(event) {
                event.preventDefault();
                const { expanded } = this.get();
                this.set({ expanded: !expanded });
            },
            toggleSelect(k, event) {
                event.preventDefault();
                const { selected } = this.get();
                const i = selected.indexOf(k);
                if (event.shiftKey) {
                    if (i > -1) selected.splice(i, 1);
                    else selected.push(k);
                } else {
                    selected.length = 1;
                    selected[0] = k;
                }
                this.set({ selected });
            },
            getColor(color) {
                const { palette } = this.get();
                return getColor(color, palette);
            },
            reset() {
                const { selected, custom } = this.get();
                const custom2 = clone(custom);
                selected.forEach(k => delete custom2[k]);
                this.set({ custom: custom2 });
            },
            resetAll() {
                this.set({ custom: {} });
            },
            selectAll(event) {
                event.preventDefault();
                const { selected, colorKeys } = this.get();
                colorKeys.forEach(k => {
                    if (selected.indexOf(k.key) < 0) selected.push(k.key);
                });
                this.set({ selected });
            },
            selectNone(event) {
                event.preventDefault();
                const { selected } = this.get();
                selected.length = 0;
                this.set({ selected });
            },
            selectInvert(event) {
                event.preventDefault();
                const { selected, colorKeys } = this.get();
                colorKeys.forEach(k => {
                    const i = selected.indexOf(k.key);
                    if (i < 0) selected.push(k.key);
                    else selected.splice(i, 1);
                });
                this.set({ selected });
            }
        },
        onstate({ previous, changed, current }) {
            if (previous && changed.custom && current.custom) {
                let c = current.custom;
                if (c && c.length === 0) {
                    c = {};
                }
                this.set({ custom: c });
            }
        }
    };

    function stripTags(s) {
        return purifyHtml(s, '');
    }
</script>

<style>
    .custom-color-selector-body {
        display: flex;
        width: 100%;
        margin-bottom: 15px;
    }
    .custom-color-selector-list {
        width: 170px;
    }
    .custom-color-selector-aside {
        flex: 1;
        padding-left: 15px;
    }
    .selection-controls {
        text-align: left;
        font-size: 12px;
    }
    .selection-controls a {
        padding-left: 4px;
    }
    .selection-color-picker {
        display: inline-block;
        padding-bottom: 10px;
    }
    .custom-color-selector-body h4 {
        margin: 0 0 10px;
        font-size: 14px;
        color: #444;
    }
    .custom-color-selector-body li .color {
        width: 17px;
        height: 17px;
        float: left;
        background: #ccc;
        text-align: center;
        line-height: 14px;
        color: #fff;
        font-size: 20px;
        font-weight: bold;
    }
    .custom-color-selector-body .dataseries {
        border-radius: 5px;
        max-height: 220px;
        overflow: auto;
        padding: 3px 0;
        margin-bottom: 4px;
        background: #fff;
        border-top: 1px solid #aaa;
        border-left: 1px solid #aaa;
        border-bottom: 1px solid #ccc;
        border-right: 1px solid #ccc;
        box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.1);
    }
    .custom-color-selector-body .dataseries li {
        padding: 3px 5px 3px 8px;
        cursor: pointer;
        border-top: 1px solid rgba(0, 0, 0, 0.075);
    }
    .custom-color-selector-body .dataseries li:nth-child(2n) {
        background: rgba(128, 128, 128, 0.05);
    }
    .custom-color-selector-body .dataseries li:first-child {
        border-top: 0;
    }
    .custom-color-selector-body .dataseries li.selected {
        background: #18a1cd22;
    }
    .custom-color-selector-body .dataseries li.selected + li {
        border-top-color: #c6d9df;
    }
    .custom-color-selector-body .dataseries label {
        padding-left: 25px;
        line-height: 1.3;
        min-height: 1.3em;
        color: #555;
        font-size: 13px;
    }
    .custom-color-selector-body .dataseries .selected label {
        font-weight: bold;
        color: #000;
    }
</style>
